from enum import Enum
from typing import Optional, List, Set, Dict, Union
from pydantic import BaseModel, Field, HttpUrl, EmailStr
from fastapi import FastAPI, Query, Path, Body, Cookie, Header, status, Form,  File, UploadFile, HTTPException, Request, Depends
from fastapi.responses import HTMLResponse, JSONResponse
from fastapi.encoders import jsonable_encoder
from fastapi.security import OAuth2PasswordBearer
from fastapi.middleware.cors import CORSMiddleware
from datetime import datetime, time, timedelta
from uuid import UUID

app = FastAPI(title="my fastapi")


@app.get("/")
async def root():
    return {"message": "Hello World"}

@app.get("/uploadFiles")
async def main():
    content = """
<body>
<form action="/uploadfiles58/" enctype="multipart/form-data" method="post">
<input name="files" type="file" multiple>
<input type="submit">
</form>
<form action="/uploadfiles58/" enctype="multipart/form-data" method="post">
<input name="files" type="file" multiple>
<input type="submit">
</form>
</body>
    """
    return HTMLResponse(content=content)


# @app.get("/items/{item_id}")
# async def read_item(item_id: int):
#     return {"item_id": item_id}

class ModelName(str, Enum):
    alexnet = "alexnet"
    resnet = "resnet"
    lenet = "lenet"


@app.get("/models/{model_name}")
async def get_model(model_name: ModelName):
    if model_name == ModelName.alexnet:
        return {"model_name": model_name, "message": "Deep Learning FTW!"}

    if model_name.value == "lenet":
        return {"model_name": model_name, "message": "LeCNN all the images"}

    return {"model_name": model_name, "message": "Have some residuals"}


fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]


# @app.get("/items/")
# async def read_item(skip: int = 0, limit: int = 10):
#     return fake_items_db[skip: skip + limit]


# 你可以将它们的默认值设置为 None 来声明可选查询参数

@app.get("/items/{item_id}")
async def read_item(item_id: str, q: Optional[str] = None):
    if q:
        return {"item_id": item_id, "q": q}
    return {"item_id": item_id}


# 自动转换
@app.get("/items2/{item_id}")
async def read_item(item_id: str, q: Optional[str] = None, short: bool = False):
    item = {"item_id": item_id}
    if q:
        item.update({"q": q})
    if not short:
        item.update(
            {"description": "This is an amazing item that has a long description"}
        )
    return item


@app.get("/users/{user_id}/items/{item_id}")
async def read_user_item(
    user_id: int, item_id: str, q: Optional[str] = None, short: bool = False
):
    item = {"item_id": item_id, "owner_id": user_id}
    if q:
        item.update({"q": q})
    if not short:
        item.update(
            {"description": "This is an amazing item that has a long description"}
        )
    return item


# 必需查询参数
@app.get("/items3/{item_id}")
async def read_user_item(item_id: str, needy: str):
    item = {"item_id": item_id, "needy": needy}
    return item


@app.get("/items4/{item_id}")
async def read_user_item(
    item_id: str, needy: str, skip: int = 0, limit: Optional[int] = None
):
    item = {"item_id": item_id, "needy": needy, "skip": skip, "limit": limit}
    return item


class Item(BaseModel):
    name: str  # 必须
    description: Optional[str] = None  # 可选 # 和声明查询参数时一样，当一个模型属性具有默认值时，它不是必需的。否则它是一个必需属性。将默认值设为 None 可使其成为可选属性
    price: float
    tax: Optional[float] = None
    min: int = 1


@app.post("/items5/")
async def create_item(item: Item):
    return item


class Item2(BaseModel):
    name: str
    description: Optional[str] = None
    price: float
    tax: Optional[float] = None


@app.post("/items6/")
async def create_item(item: Item2):
    return item


@app.get("/items7/")
async def read_items(q: Optional[str] = None):
    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
    if q:
        results.update({"q": q})
    return results
# 查询参数 q 的类型为 str，默认值为 None，因此它是可选的。


@app.get("/items8/")
async def read_items(q: Optional[str] = Query(None, max_length=50)):
    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
    if q:
        results.update({"q": q})
    return results


@app.get("/items8/")
async def read_items(q: Optional[str] = Query(None, min_length=3, max_length=50)):
    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
    if q:
        results.update({"q": q})
    return results


@app.get("/items9/")
async def read_items(
    q: Optional[str] = Query(None, min_length=3, max_length=50, regex="^fixedquery$")
):
    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
    if q:
        results.update({"q": q})
    return results


@app.get("/items10/")
async def read_items(q: str = Query(..., min_length=3)):
    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
    if q:
        results.update({"q": q})
    return results

@app.get("/items11/")
async def read_items(q: Optional[List[str]] = Query(None)):
    query_items = {"q": q}
    return query_items
#  http://localhost:8000/items/?q=foo&q=bar


@app.get("/items12/")
async def read_items(q: List[str] = Query(["foo", "bar"])):
    query_items = {"q": q}
    return query_items


@app.get("/items13/")
async def read_items(q: list = Query([])):
    query_items = {"q": q}
    return query_items


@app.get("/items14/")
async def read_items(
    q: Optional[str] = Query(None, title="Query string", min_length=3)
):
    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
    if q:
        results.update({"q": q})
    return results


@app.get("/items15/")
async def read_items(
    q: Optional[str] = Query(
        None,
        title="qs",
        description="Query string for the items to search in the database that have a good match",
        min_length=3,
    )
):
    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
    if q:
        results.update({"q": q})
    return results


@app.get("/items16/")
async def read_items(q: Optional[str] = Query(None, alias="item-query")):
    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
    if q:
        results.update({"q": q})
    return results


@app.get("/items17/")
async def read_items(
    q: Optional[str] = Query(
        None,
        alias="item-query",
        title="Query string",
        description="Query string for the items to search in the database that have a good match",
        min_length=3,
        max_length=50,
        regex="^fixedquery$",
        deprecated=True,
    )
):
    results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
    if q:
        results.update({"q": q})
    return results


class Item18(BaseModel):
    name: str
    description: Optional[str] = None # 可选参数
    price: float
    tax: Optional[float] = None


@app.put("/items18/{item_id}")
async def update_item18(
    *, # 可变参数
    item_id: int = Path(..., title="The ID of the item to get", ge=0, le=1000),
    q: Optional[str] = None,
    item: Optional[Item18] = None, # 如果是BaseModel的子类，将作为请求体里的内容获取
):
    results = {"item_id": item_id}
    if q:
        results.update({"q": q})
    if item:
        results.update({"item": item})
    return results




class Item19(BaseModel):
    name: str
    description: Optional[str] = None
    price: float
    tax: Optional[float] = None


class User19(BaseModel):
    username: str
    full_name: Optional[str] = None

# 在这种情况下，FastAPI 将注意到该函数中有多个请求体参数（两个 Pydantic 模型参数）。因此，它将使用参数名称作为请求体中的键（字段名称），并期望一个类似于以下内容的请求体
@app.put("/items19/{item_id}")
async def update_item(item_id: int, item: Item19, user: User19):
    results = {"item_id": item_id, "item": item, "user": user}
    return results



class Item20(BaseModel):
    name: str
    description: Optional[str] = None
    price: float
    tax: Optional[float] = None


class User20(BaseModel):
    username: str
    full_name: Optional[str] = None


@app.put("/items20/{item_id}")
async def update_item(
    item_id: int, item: Item20, user: User20, importance: int = Body(...)
):
    results = {"item_id": item_id, "item": item, "user": user, "importance": importance}
    return results




class Item21(BaseModel):
    name: str
    description: Optional[str] = None
    price: float
    tax: Optional[float] = None


class User21(BaseModel):
    username: str
    full_name: Optional[str] = None


@app.put("/items21/{item_id}")
async def update_item(
    *,
    item_id: int,
    item: Item21,
    user: User21,
    importance: int = Body(..., gt=0),
    q: Optional[str] = None
):
    results = {"item_id": item_id, "item": item, "user": user, "importance": importance}
    if q:
        results.update({"q": q})
    return results


class Item22(BaseModel):
    name: str
    description: Optional[str] = None
    price: float
    tax: Optional[float] = None


@app.put("/items22/{item_id}")
async def update_item(item_id: int, item: Item22 = Body(..., embed=True)):
    results = {"item_id": item_id, "item": item}
    return results


class Item23(BaseModel):
    name: str
    description: Optional[str] = Field(
        None, title="The description of the item", max_length=300
    )
    price: float = Field(..., gt=0, description="The price must be greater than zero")
    tax: Optional[float] = None


@app.put("/items23/{item_id}")
async def update_item(item_id: int, item: Item23 = Body(..., embed=True)):
    results = {"item_id": item_id, "item": item}
    return results


class Item24(BaseModel):
    name: str
    description: Optional[str] = Field(
        None, title="The description of the item", max_length=300
    )
    price: float = Field(..., gt=0, description="The price must be greater than zero")
    tax: Optional[float] = None


@app.put("/items24/{item_id}")
async def update_item(item_id: int, item: Item24 = Body(..., embed=True)):
    results = {"item_id": item_id, "item": item}
    return results


class Item25(BaseModel):
    name: str
    description: Optional[str] = None
    price: float
    tax: Optional[float] = None
    tags: list = []


@app.put("/items25/{item_id}")
async def update_item(item_id: int, item: Item25):
    results = {"item_id": item_id, "item": item}
    return results


class Item26(BaseModel):
    name: str
    description: Optional[str] = None
    price: float
    tax: Optional[float] = None
    tags: List[str] = []


@app.put("/items26/{item_id}")
async def update_item(item_id: int, item: Item26):
    results = {"item_id": item_id, "item": item}
    return results


class Item27(BaseModel):
    name: str
    description: Optional[str] = None
    price: float
    tax: Optional[float] = None
    tags: Set[str] = set()


@app.put("/items27/{item_id}")
async def update_item(item_id: int, item: Item27):
    results = {"item_id": item_id, "item": item}
    return results



class Image28(BaseModel):
    url: str
    name: str


class Item28(BaseModel):
    name: str
    description: Optional[str] = None
    price: float
    tax: Optional[float] = None
    tags: Set[str] = []
    image: Optional[Image28] = None


@app.put("/items28/{item_id}")
async def update_item(item_id: int, item: Item28):
    results = {"item_id": item_id, "item": item}
    return results


class Image29(BaseModel):
    url: str
    name: str


class Item29(BaseModel):
    name: str
    description: Optional[str] = None
    price: float
    tax: Optional[float] = None
    tags: Set[str] = []
    image: Optional[Image29] = None


@app.put("/items29/{item_id}")
async def update_item(item_id: int, item: Item29):
    results = {"item_id": item_id, "item": item}
    return results


class Image30(BaseModel):
    url: HttpUrl
    name: str


class Item30(BaseModel):
    name: str
    description: Optional[str] = None
    price: float
    tax: Optional[float] = None
    tags: Set[str] = set()
    image: Optional[Image30] = None


@app.put("/items30/{item_id}")
async def update_item(item_id: int, item: Item30):
    results = {"item_id": item_id, "item": item}
    return results



class Image31(BaseModel):
    url: HttpUrl
    name: str


class Item31(BaseModel):
    name: str
    description: Optional[str] = None
    price: float
    tax: Optional[float] = None
    tags: Set[str] = set()
    images: Optional[List[Image31]] = None


@app.put("/items31/{item_id}")
async def update_item(item_id: int, item: Item31):
    results = {"item_id": item_id, "item": item}
    return results



class Image32(BaseModel):
    url: HttpUrl
    name: str


class Item32(BaseModel):
    name: str
    description: Optional[str] = None
    price: float
    tax: Optional[float] = None
    tags: Set[str] = set()
    images: Optional[List[Image32]] = None


class Offer32(BaseModel):
    name: str
    description: Optional[str] = None
    price: float
    items: List[Item32]


@app.post("/offers32/")
async def create_offer(offer: Offer32):
    return offer


class Image33(BaseModel):
    url: HttpUrl
    name: str


@app.post("/images33/multiple/")
async def create_multiple_images(images: List[Image33]):
    return images



# 请记住 JSON 仅支持将 str 作为键。
# 但是 Pydantic 具有自动转换数据的功能。
# 这意味着，即使你的 API 客户端只能将字符串作为键发送，只要这些字符串内容仅包含整数，Pydantic 就会对其进行转换并校验。
# 然后你接收的名为 weights 的 dict 实际上将具有 int 类型的键和 float 类型的值
@app.post("/index-weights/")
async def create_index_weights(weights: Dict[int, float]):
    return weights




class Item34(BaseModel):
    name: str
    description: Optional[str] = None
    price: float
    tax: Optional[float] = None

    class Config:
        schema_extra = {
            "example": {
                "name": "Foo",
                "description": "A very nice Item",
                "price": 35.4,
                "tax": 3.2,
            }
        }


@app.put("/items34/{item_id}")
async def update_item(item_id: int, item: Item34):
    results = {"item_id": item_id, "item": item}
    return results


class Item35(BaseModel):
    name: str = Field(..., example="Foo")
    description: Optional[str] = Field(None, example="A very nice Item")
    price: float = Field(..., example=35.4)
    tax: Optional[float] = Field(None, example=3.2)


@app.put("/items35/{item_id}")
async def update_item(item_id: int, item: Item35):
    results = {"item_id": item_id, "item": item}
    return results


class Item36(BaseModel):
    name: str
    description: Optional[str] = None
    price: float
    tax: Optional[float] = None


@app.put("/items36/{item_id}")
async def update_item(
    item_id: int,
    item: Item36 = Body(
        ...,
        example={
            "name": "Foo",
            "description": "A very nice Item",
            "price": 35.4,
            "tax": 3.2,
        },
    ),
):
    results = {"item_id": item_id, "item": item}
    return results


@app.put("/items37/{item_id}")
async def read_items(
    item_id: UUID,
    start_datetime: Optional[datetime] = Body(None),
    end_datetime: Optional[datetime] = Body(None),
    repeat_at: Optional[time] = Body(None),
    process_after: Optional[timedelta] = Body(None),
):
    start_process = start_datetime + process_after
    duration = end_datetime - start_process
    return {
        "item_id": item_id,
        "start_datetime": start_datetime,
        "end_datetime": end_datetime,
        "repeat_at": repeat_at,
        "process_after": process_after,
        "start_process": start_process,
        "duration": duration,
    }


@app.put("/items38/{item_id}")
async def read_items(
    item_id: UUID,
    start_datetime: Optional[datetime] = Body(None),
    end_datetime: Optional[datetime] = Body(None),
    repeat_at: Optional[time] = Body(None),
    process_after: Optional[timedelta] = Body(None),
):
    start_process = start_datetime + process_after
    duration = end_datetime - start_process
    return {
        "item_id": item_id,
        "start_datetime": start_datetime,
        "end_datetime": end_datetime,
        "repeat_at": repeat_at,
        "process_after": process_after,
        "start_process": start_process,
        "duration": duration,
    }


@app.get("/items39/")
async def read_items(ads_id: Optional[str] = Cookie(None)):
    return {"ads_id": ads_id}

@app.get("/items40/")
async def read_items(user_agent: Optional[str] = Header(None)):
    return {"User-Agent": user_agent}

@app.get("/items41/")
async def read_items(
    strange_header: Optional[str] = Header(None, convert_underscores=True),
    user_agent: Optional[str] = Header(None)
):
    return {"strange_header": strange_header, "User-Agent": user_agent }


@app.get("/items42/")
async def read_items(x_token: Optional[List[str]] = Header(None)):
    return {"X-Token values": x_token}


class Item43(BaseModel):
    name: str
    description: Optional[str] = None
    price: float
    tax: Optional[float] = None
    tags: List[str] = []


@app.post("/items43/", response_model=Item43)
async def create_item(item: Item):
    return item



class UserIn44(BaseModel):
    username: str
    password: str
    email: EmailStr
    full_name: Optional[str] = None


# Don't do this in production!
@app.post("/user44/", response_model=UserIn44)
async def create_user(user: UserIn44):
    return user



class UserIn45(BaseModel):
    username: str
    password: str
    email: EmailStr
    full_name: Optional[str] = None


class UserOut45(BaseModel):
    username: str
    email: EmailStr
    full_name: Optional[str] = None


@app.post("/user45/", response_model=UserOut45)
async def create_user(user: UserIn45):
    return user




class Item46(BaseModel):
    name: str
    description: Optional[str] = None
    price: float
    tax: float = 10.5
    tags: List[str] = []


items46 = {
    "foo": {"name": "Foo", "price": 50.2},
    "bar": {"name": "Bar", "description": "The bartenders", "price": 62, "tax": 20.2},
    "baz": {"name": "Baz", "description": None, "price": 50.2, "tax": 10.5, "tags": []},
}


@app.get("/items46/{item_id}", response_model=Item46, response_model_exclude_unset=True) # response_model_exclude_unset=True -> 然后响应中将不会包含那些默认值，而是仅有实际设置的值
async def read_item(item_id: str):
    return items46[item_id]





class Item47(BaseModel):
    name: str
    description: Optional[str] = None
    price: float
    tax: float = 10.5


items47 = {
    "foo": {"name": "Foo", "price": 50.2},
    "bar": {"name": "Bar", "description": "The Bar fighters", "price": 62, "tax": 20.2},
    "baz": {
        "name": "Baz",
        "description": "There goes my baz",
        "price": 50.2,
        "tax": 10.5,
    },
}


@app.get(
    "/items47/{item_id}/name",
    response_model=Item47,
    response_model_include={"name", "description"},
)
async def read_item_name(item_id: str):
    return items47[item_id]


@app.get("/items48/{item_id}/public", response_model=Item47, response_model_exclude={"tax"})
async def read_item_public_data(item_id: str):
    return items47[item_id]





class UserIn49(BaseModel):
    username: str
    password: str
    email: EmailStr
    full_name: Optional[str] = None


class UserOut49(BaseModel):
    username: str
    email: EmailStr
    full_name: Optional[str] = None


class UserInDB49(BaseModel):
    username: str
    hashed_password: str
    email: EmailStr
    full_name: Optional[str] = None


def fake_password_hasher(raw_password: str):
    return "supersecret" + raw_password


def fake_save_user(user_in: UserIn49):
    hashed_password = fake_password_hasher(user_in.password)
    user_in_db = UserInDB49(**user_in.dict(), hashed_password=hashed_password)
    print("User saved! ..not really")
    return user_in_db


@app.post("/user49/", response_model=UserOut49)
async def create_user(user_in: UserIn49):
    user_saved = fake_save_user(user_in)
    return user_saved



class UserBase50(BaseModel):
    username: str
    email: EmailStr
    full_name: Optional[str] = None


class UserIn50(UserBase50):
    password: str


class UserOut50(UserBase50):
    pass


class UserInDB50(UserBase50):
    hashed_password: str


def fake_password_hasher(raw_password: str):
    return "supersecret" + raw_password


def fake_save_user(user_in: UserIn50):
    hashed_password = fake_password_hasher(user_in.password)
    user_in_db = UserInDB50(**user_in.dict(), hashed_password=hashed_password)
    print("User saved! ..not really")
    return user_in_db


@app.post("/user50/", response_model=UserOut50)
async def create_user(user_in: UserIn50):
    user_saved = fake_save_user(user_in)
    return user_saved


class BaseItem51(BaseModel):
    description: str
    type: str


class CarItem51(BaseItem51):
    type = "car"


class PlaneItem51(BaseItem51):
    type = "plane"
    size: int


items = {
    "item1": {"description": "All my friends drive a low rider", "type": "car"},
    "item2": {
        "description": "Music is my aeroplane, it's my aeroplane",
        "type": "plane",
        "size": 5,
    },
}


@app.get("/items51/{item_id}", response_model=Union[PlaneItem51, CarItem51])
async def read_item(item_id: str):
    return items[item_id]


class Item52(BaseModel):
    name: str
    description: str


items = [
    {"name": "Foo", "description": "There comes my hero"},
    {"name": "Red", "description": "It's my aeroplane"},
]


@app.get("/items52/", response_model=List[Item52])
async def read_items():
    return items


@app.get("/keyword-weights53/", response_model=Dict[str, float]) # dict的key为str value为float
async def read_keyword_weights():
    return {"foo": 2.3, "bar": 3.4}


@app.post("/items54/", status_code=status.HTTP_201_CREATED)
async def create_item(name: str):
    return {"name": name}


@app.post("/login55/")
async def login(username: str = Form(...), password: str = Form(...)):
    return {"username": username, "password": password}



@app.post("/files56/")
async def create_file(file: bytes = File(...)):
    return {"file_size": len(file)}


@app.post("/uploadfile57/")
async def create_upload_file(file: UploadFile):  # 不过，很多情况下，UploadFile 更好用。
    return {"filename": file.filename}



@app.post("/uploadfiles58/")
async def create_upload_files(files: List[UploadFile]):
    return {"filenames": [file.filename for file in files]}




@app.post("/files59/")
async def create_file(
    file: bytes = File(...), fileb: UploadFile = File(...), token: str = Form(...)
):
    return {
        "file_size": len(file),
        "token": token,
        "fileb_content_type": fileb.content_type,
    }



items60 = [ 'hello' ]


@app.get("/items60/{item_id}")
async def read_item(item_id: str):
    if item_id not in items60:
        raise HTTPException(status_code=404, detail="Item not found")
    return {"item": 'ok-' + item_id }


@app.get("/items-header61/{item_id}")
async def read_item_header(item_id: str):
    if item_id not in items60:
        raise HTTPException(
            status_code=404,
            detail="Item not found",
            headers={"X-Error": "There goes my error"},
        )
    return {"item": item_id}


# 自定义异常处理- 1. 自定义异常类
class UnicornException(Exception):
    def __init__(self, name: str):
        self.name = name

# 通过app.exception_handler接收这个异常类，内部写下处理这个异常的处理机制
@app.exception_handler(UnicornException)
async def unicorn_exception_handler(request: Request, exc: UnicornException):
    return JSONResponse(
        status_code=418,
        content={"message": f"Oops! {exc.name} did something. There goes a rainbow..."},
    )


@app.get("/unicorns62/{name}")
async def read_unicorn(name: str):
    if name == "yolo":
        raise UnicornException(name=name) # 抛出自定义的异常类
    return {"unicorn_name": name}




class Item63(BaseModel):
    name: Optional[str] = None
    description: Optional[str] = None
    price: Optional[float] = None
    tax: float = 10.5
    tags: List[str] = []  # ？ todo


items63 = {
    "foo": {"name": "Foo", "price": 50.2},
    "bar": {"name": "Bar", "description": "The bartenders", "price": 62, "tax": 20.2},
    "baz": {"name": "Baz", "description": None, "price": 50.2, "tax": 10.5, "tags": []},
}


@app.get("/items63_01/{item_id}", response_model=Item63)
async def read_item(item_id: str):
    return items63[item_id]


@app.put("/items63/{item_id}", response_model=Item63)
async def update_item(item_id: str, item: Item63):
    print(type(item))
    update_item_encoded = jsonable_encoder(item) # jsonable_encoder(item)
    print(update_item_encoded)
    print(type(update_item_encoded))
    items63[item_id] = update_item_encoded
    return update_item_encoded




class Item64(BaseModel):
    name: Optional[str] = None
    description: Optional[str] = None
    price: Optional[float] = None
    tax: float = 10.5
    tags: List[str] = []


items64 = {
    "foo": {"name": "Foo", "price": 50.2},
    "bar": {"name": "Bar", "description": "The bartenders", "price": 62, "tax": 20.2},
    "baz": {"name": "Baz", "description": None, "price": 50.2, "tax": 10.5, "tags": []},
}


@app.get("/items64_01/{item_id}", response_model=Item64)
async def read_item(item_id: str):
    return items[item_id]


@app.patch("/items64/{item_id}", response_model=Item64)
async def update_item(item_id: str, item: Item64):
    stored_item_data = items64[item_id]
    stored_item_model = Item64(**stored_item_data)
    update_data = item.dict(exclude_unset=True)
    updated_item = stored_item_model.copy(update=update_data)
    items64[item_id] = jsonable_encoder(updated_item)
    return updated_item



async def common_parameters65(q: Optional[str] = None, skip: int = 0, limit: int = 100):
    return {"q": q, "skip": skip, "limit": limit}


@app.get("/items65/")
async def read_items(commons: dict = Depends(common_parameters65)): # 1. 这里只能传给 Depends 一个参数 2.且该参数必须是可调用对象，比如函数 3. 该函数接收的参数和路径操作函数的参数一样
    return commons


@app.get("/users65/")
async def read_users(commons: dict = Depends(common_parameters65)):
    return commons



fake_items_db66 = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]


class CommonQueryParams66:
    def __init__(self, q: Optional[str] = None, skip: int = 0, limit: int = 100):
        self.q = q
        self.skip = skip
        self.limit = limit


@app.get("/items66/")
async def read_items(commons: CommonQueryParams66 = Depends(CommonQueryParams66)):
    response = {}
    if commons.q:
        response.update({"q": commons.q})
    items = fake_items_db[commons.skip : commons.skip + commons.limit]
    response.update({"items": items})
    return response




def query_extractor67(q: Optional[str] = None):
    return q


def query_or_cookie_extractor67(
    q: str = Depends(query_extractor67), last_query: Optional[str] = Cookie(None)
):
    if not q:
        return last_query
    return q


@app.get("/items67/")
async def read_query(query_or_default: str = Depends(query_or_cookie_extractor67)):
    return {"q_or_cookie": query_or_default}


# 在路径操作装饰器中添加 dependencies 参数
async def verify_token68(x_token: str = Header(...)):
    if x_token != "fake-super-secret-token":
        raise HTTPException(status_code=400, detail="X-Token header invalid")


async def verify_key68(x_key: str = Header(...)):
    if x_key != "fake-super-secret-key":
        raise HTTPException(status_code=400, detail="X-Key header invalid")
    return x_key


@app.get("/items68/", dependencies=[Depends(verify_token68), Depends(verify_key68)])
async def read_items():
    return [{"item": "Foo"}, {"item": "Bar"}]


# 全局 路径装饰器依赖项
# async def verify_token(x_token: str = Header(...)):
#     if x_token != "fake-super-secret-token":
#         raise HTTPException(status_code=400, detail="X-Token header invalid")
# async def verify_key(x_key: str = Header(...)):
#     if x_key != "fake-super-secret-key":
#         raise HTTPException(status_code=400, detail="X-Key header invalid")
#     return x_key
# app = FastAPI(dependencies=[Depends(verify_token), Depends(verify_key)])



# oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")


# @app.get("/items69/")
# async def read_items(token: str = Depends(oauth2_scheme)):
#     return {"token": token}

# 中间件
@app.middleware("http")
async def add_process_time_header(request: Request, call_next):
    start_time = time.time()
    response = await call_next(request)
    process_time = time.time() - start_time
    response.headers["X-Process-Time"] = str(process_time)
    return response


# cros
origins = [
    "http://localhost.tiangolo.com",
    "https://localhost.tiangolo.com",
    "http://localhost",
    "http://localhost:8080",
]

app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)
